// winperf4j.cpp : Defines the exported functions for the DLL application.
//

#include "stdafx.h"
#include "winperf4j.h"
#include <pdh.h>
#include <windows.h>


// Based on Angry IP Scanner source code

FARPROC IcmpCreateFile = NULL;
typedef BOOL (FAR WINAPI *TIcmpCloseHandle)(HANDLE IcmpHandle);
TIcmpCloseHandle IcmpCloseHandle = NULL;


typedef DWORD (FAR WINAPI *TIcmpSendEcho)(
  HANDLE IcmpHandle, 	/* handle returned from IcmpCreateFile() */  
  unsigned long DestAddress, /* destination IP address (in network order) */  
  LPVOID RequestData, /* pointer to buffer to send */  
  WORD RequestSize,	/* length of data in buffer */  
  LPVOID RequestOptns,  /* see Note 2 */  
  LPVOID ReplyBuffer, /* see Note 1 */  
  DWORD ReplySize, 	/* length of reply (must allow at least 1 reply) */  
  DWORD Timeout 	/* time in milliseconds to wait for reply */
);
TIcmpSendEcho IcmpSendEcho = NULL;


JNIEXPORT jint JNICALL Java_com_google_code_openperfmon_monapi_win_WinIcmp_icmpCreateFile
  (JNIEnv *, jclass)
{
  // Initialize dlls on first use
  if (IcmpCreateFile == NULL) {
    HMODULE hICMP = LoadLibrary(L"icmp.dll");
    if (!hICMP) {
      // newer versions of Windows should include this one instead
      hICMP = LoadLibrary(L"iphlpapi.dll");
    }

    if (!hICMP) {
      return -1;
    }

    IcmpCreateFile  = (FARPROC) GetProcAddress(hICMP, "IcmpCreateFile");
    IcmpCloseHandle = (TIcmpCloseHandle) GetProcAddress(hICMP, "IcmpCloseHandle");
    IcmpSendEcho    = (TIcmpSendEcho) GetProcAddress(hICMP, "IcmpSendEcho");
  }

  return IcmpCreateFile();
}

JNIEXPORT jint JNICALL Java_com_google_code_openperfmon_monapi_win_WinIcmp_icmpSendEcho
  (JNIEnv *env, jclass cls, jint handle, jbyteArray address, jbyteArray pingData, jbyteArray replyData, jint timeout)
{
  DWORD replyCount;
  jbyte *addrBuf, *pingDataBuf, *replyDataBuf;
  jint pingDataLen, replyDataLen;
  unsigned long ip;

  addrBuf = env->GetByteArrayElements(address, NULL);
  pingDataBuf = env->GetByteArrayElements(pingData, NULL);
  replyDataBuf = env->GetByteArrayElements(replyData, NULL);

  pingDataLen = env->GetArrayLength(pingData);
  replyDataLen = env->GetArrayLength(replyData);

  ip = *((unsigned long*)addrBuf);
  replyCount = IcmpSendEcho((HANDLE)handle, ip, pingDataBuf, pingDataLen,
                            NULL, replyDataBuf, replyDataLen, timeout);
                            
  env->ReleaseByteArrayElements(address, addrBuf, JNI_ABORT);
  env->ReleaseByteArrayElements(pingData, pingDataBuf, JNI_ABORT);
  env->ReleaseByteArrayElements(replyData, replyDataBuf, 0);
  
  return replyCount;
}

JNIEXPORT void JNICALL Java_com_google_code_openperfmon_monapi_win_WinIcmp_icmpCloseHandle
  (JNIEnv *, jclass, jint handle)
{
	IcmpCloseHandle((HANDLE)handle);
}

/*JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_WinApi_logonUser
  (JNIEnv * env, jclass cls, jstring user, jstring domain, jstring password)
{
	LPWSTR lpwUser = (LPWSTR)env->GetStringChars(user, NULL);
	LPWSTR lpwDomain = (LPWSTR)env->GetStringChars(domain, NULL);
	LPWSTR lpwPasword = (LPWSTR)env->GetStringChars(password, NULL);

	HANDLE userHandle = NULL;
	LogonUser(lpwUser, lpwDomain, lpwPasword, LOGON32_LOGON_NEW_CREDENTIALS, LOGON32_PROVIDER_DEFAULT, &userHandle);

	env->ReleaseStringChars(user, (const jchar *)lpwUser);
	env->ReleaseStringChars(domain, (const jchar *)lpwDomain);
	env->ReleaseStringChars(password, (const jchar *)lpwPasword);

	return (jint)userHandle;
}

JNIEXPORT jboolean JNICALL Java_com_google_code_winperf4j_WinApi_impersonate
  (JNIEnv *, jclass, jint handle)
{
	return (jboolean)ImpersonateLoggedOnUser((HANDLE)handle);
}

JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_WinApi_getLastError
  (JNIEnv *, jclass)
{
	return (jint)GetLastError();
}

JNIEXPORT void JNICALL Java_com_google_code_winperf4j_WinApi_closeHandle
  (JNIEnv * env, jclass, jint handle)
{
	CloseHandle((HANDLE)handle);
}

static LPWSTR PC_QUERY = L"\\\\192.168.3.126\\Memory\\Available Bytes";
JNIEXPORT jdouble JNICALL Java_com_google_code_winperf4j_WinApi_testCounter
  (JNIEnv *, jclass)
{
	double res = 0;
	PDH_HQUERY query = NULL;
	printf("Trying PdhOpenQuery\n");
	PDH_STATUS stat = PdhOpenQuery(NULL, NULL, &query);
	if (stat != ERROR_SUCCESS)
	{
		printf("Error PdhOpenQuery: %d!\n", stat);
		goto cleanup;
	}

	printf("Trying PdhAddCounter\n");
	PDH_HCOUNTER counter;
	stat = PdhAddCounter(query, PC_QUERY, NULL, &counter);
	if (stat != ERROR_SUCCESS)
	{
		printf("Error %d\n", stat);
		goto cleanup;
	}

	printf("Trying PdhCollectQueryData\n");
	stat = PdhCollectQueryData(query);
	if (stat != ERROR_SUCCESS)
	{
		printf("Error %d\n", stat);
		goto cleanup;
	}
	
	Sleep(1000);

	printf("Trying PdhCollectQueryData again\n");
	stat = PdhCollectQueryData(query);
	if (stat != ERROR_SUCCESS)
	{
		printf("Error %d\n", stat);
		goto cleanup;
	}

	printf("Trying PdhGetFormattedCounterValue\n");
	PDH_FMT_COUNTERVALUE  fmtValue;
	DWORD type;
	stat = PdhGetFormattedCounterValue(counter, PDH_FMT_DOUBLE, &type, &fmtValue);
	if (stat != ERROR_SUCCESS)
	{
		printf("Error %d\n", stat);
		goto cleanup;
	}
	printf("PdhGetFormattedCounterValue OK: %f\n", fmtValue.doubleValue);
	res = fmtValue.doubleValue;

cleanup:
	if (query != NULL) PdhCloseQuery(query);

	return res;
}

JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_PdhQuery_pdhOpenQuery
  (JNIEnv *, jclass)
{
	PDH_HQUERY query = NULL;
	PdhOpenQuery(NULL, NULL, &query);
	return (jint)query;
}

static jfieldID counterHandleId;
static jfieldID counterResultId;

JNIEXPORT void JNICALL Java_com_google_code_winperf4j_PdhQuery_initIds
  (JNIEnv * env, jclass, jclass counterClass)
{
	counterHandleId = env->GetFieldID(counterClass, "counterHandle", "I");
	counterResultId = env->GetFieldID(counterClass, "counterResult", "D");
}

JNIEXPORT void JNICALL Java_com_google_code_winperf4j_PdhQuery_pdhCloseQuery
  (JNIEnv *, jclass, jint query)
{
	if (query != NULL) PdhCloseQuery((PDH_HQUERY)query);
}



JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_PdhQuery_pdhAddCounter
  (JNIEnv * env, jclass, jint query, jstring path, jobject counterResult)
{
	LPWSTR lpwPath = (LPWSTR)env->GetStringChars(path, NULL);
	PDH_HCOUNTER counter;
	PDH_STATUS stat = PdhAddCounter((PDH_HQUERY)query, lpwPath, NULL, &counter);
	if (stat == 0) env->SetIntField(counterResult, counterHandleId, (jint)counter);

	return (jint)stat;
}

JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_PdhQuery_pdhCollectQueryData
  (JNIEnv *, jclass, jint query)
{
	return (jint)PdhCollectQueryData((PDH_HQUERY)query);
}

JNIEXPORT jint JNICALL Java_com_google_code_winperf4j_PdhQuery_pdhGetFormattedCounterValue
  (JNIEnv * env, jclass, jobject counterResult)
{
	PDH_FMT_COUNTERVALUE  fmtValue;
	DWORD type;
	jint counter = env->GetIntField(counterResult, counterHandleId);
	PDH_STATUS stat = PdhGetFormattedCounterValue((PDH_HCOUNTER)counter, PDH_FMT_DOUBLE, &type, &fmtValue);
	if (stat == 0)
	{
		env->SetDoubleField(counterResult, counterResultId, (jdouble)fmtValue.doubleValue);
	}
	return (jint)stat;
}
*/
